package site.jlopen.kuscia.service.data;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;
import org.secretflow.v1alpha1.common.Common;
import org.secretflow.v1alpha1.common.Common.DataColumn;
import org.secretflow.v1alpha1.kusciaapi.Domaindata;
import org.secretflow.v1alpha1.kusciaapi.Domaindata.CreateDomainDataResponse;
import org.secretflow.v1alpha1.kusciaapi.Domaindata.CreateDomainDataResponseData;
import org.secretflow.v1alpha1.kusciaapi.Domaindata.ListDomainDataRequest;
import org.secretflow.v1alpha1.kusciaapi.Domaindata.ListDomainDataResponse;
import org.secretflow.v1alpha1.kusciaapi.Domaindata.QueryDomainDataResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;

import site.jlopen.kuscia.entity.GrpcApiInfo;
import site.jlopen.kuscia.errorcode.DatatableErrorCode;
import site.jlopen.kuscia.exception.SdkBaseException;
import site.jlopen.kuscia.model.DatatableSchema;
import site.jlopen.kuscia.model.data.KusciaDataColumnVo;
import site.jlopen.kuscia.model.data.KusciaDataValueHeaderVo;
import site.jlopen.kuscia.model.data.KusciaDataValueItemVo;
import site.jlopen.kuscia.model.data.KusciaDataVo;
import site.jlopen.kuscia.properties.KusciaAPIProperties;
import site.jlopen.kuscia.rpc.impl.KusciaDomainDataRpcImpl;
import site.jlopen.kuscia.util.UUIDUtils;

@Service
public class KusciaDataManager extends AbstractDataManager {
	private static Logger logger = LoggerFactory.getLogger(KusciaDataManager.class);
	
	@Override
	public String createDomainData(GrpcApiInfo apiInfo, 
			String datasourceId,
			String domainId,
            String tableName,
            String realName,
            String description,
            Map<String, String> attributes,
            List<DatatableSchema> datatableSchemaList
    ) {
		KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
        String domainDataId = "dd-id-" + UUIDUtils.random(8);
        List<DataColumn> values = Lists.newArrayList();
        if(null != datatableSchemaList) {
        	for (DatatableSchema schema : datatableSchemaList) {
        		if(null != schema) {
        			org.secretflow.v1alpha1.common.Common.DataColumn.Builder builder = Common.DataColumn.newBuilder().setName(schema.getFeatureName())
                            .setType(schema.getFeatureType());
        			if(StringUtils.isNotBlank(schema.getFeatureDescription())) {
        				builder.setComment(schema.getFeatureDescription());
        			}
        			values.add(builder.build());
        		}
    		}
        }
        Domaindata.CreateDomainDataRequest.Builder builder = Domaindata.CreateDomainDataRequest.newBuilder()
                        .setDomaindataId(domainDataId)
                        .setDatasourceId(datasourceId)
                        .setDomainId(domainId).setName(tableName).setType("table").setVendor("apiManual")
                        .setRelativeUri(realName).putAttributes("description", description)
						.addAllColumns(values);
        if(null != attributes) {
        	for (Map.Entry<String, String> entry : attributes.entrySet()) {
        	    String key = entry.getKey();
        	    String value = entry.getValue();
        	    builder.putAttributes(key, value);
        	}
        }
		Domaindata.CreateDomainDataRequest request = builder.build();
		CreateDomainDataResponse response = new KusciaDomainDataRpcImpl(apiProperties).createDomainData(request);
		CreateDomainDataResponseData data = response.getData();
		logger.info("data:{}", data);
		String domaindataId = data.getDomaindataId();
		logger.info("domaindataId:{}", domaindataId);
		return domaindataId;
	}

	@Override
	public void updateDomainData(GrpcApiInfo apiInfo, 
			String datasourceId,
			String domainId,
			String domainDataId,
            String tableName,
            String realName,
            String description,
            Map<String, String> attributes,
            List<DatatableSchema> datatableSchemaList
    ) {
		KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
        List<DataColumn> values = Lists.newArrayList();
        for (DatatableSchema schema : datatableSchemaList) {
        	values.add(Common.DataColumn.newBuilder().setName(schema.getFeatureName())
                    .setType(schema.getFeatureType()).setComment(schema.getFeatureDescription()).build());
		}
        Domaindata.UpdateDomainDataRequest.Builder builder = Domaindata.UpdateDomainDataRequest.newBuilder()
                .setDomainId(domainId)
                .setDomaindataId(domainDataId)
                .setName(tableName)
                .setType("table")
                .setRelativeUri(realName)
                .setDatasourceId(datasourceId)
                .addAllColumns(values)
        		;
        Domaindata.UpdateDomainDataResponse response = new KusciaDomainDataRpcImpl(apiProperties).updateDomainData(builder.build());
		logger.info("getStatus:{}", response.getStatus());
        if (response.getStatus().getCode() != 0) {
        	logger.error("update datatable failed: {}");
            throw SdkBaseException.of(DatatableErrorCode.DELETE_DATATABLE_FAILED);
        }
	}

	@Override
	public void deleteDomainData(GrpcApiInfo apiInfo, String nodeCodeId, String domaindataId) {
		KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
        Domaindata.DeleteDomainDataRequest.Builder builder = Domaindata.DeleteDomainDataRequest.newBuilder()
                .setDomainId(nodeCodeId)
                .setDomaindataId(domaindataId);
        Domaindata.DeleteDomainDataResponse response = new KusciaDomainDataRpcImpl(apiProperties).deleteDomainData(builder.build());
		logger.info("getStatus:{}", response.getStatus());
        if (response.getStatus().getCode() != 0) {
        	logger.error("delete datatable failed: code={}, message={}, nodeId={}, domaindataId={}",
                    response.getStatus().getCode(), response.getStatus().getMessage(), nodeCodeId, domaindataId);
            throw SdkBaseException.of(DatatableErrorCode.DELETE_DATATABLE_FAILED);
        }
	}

	@Override
	public String queryDomainData(GrpcApiInfo apiInfo, String nodeId, String domaindataId) {
		KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
		Domaindata.QueryDomainDataRequest request = Domaindata.QueryDomainDataRequest
        .newBuilder()
        .setData(Domaindata.QueryDomainDataRequestData.newBuilder().setDomainId(nodeId).setDomaindataId(domaindataId))
        .build();
		QueryDomainDataResponse response = new KusciaDomainDataRpcImpl(apiProperties).queryDomainData(request);
        Domaindata.DomainData data = response.getData();
		logger.info("data:{}", data);
		/*domaindataId_ = "";
		name_ = "";
		type_ = "";
		relativeUri_ = "";
		domainId_ = "";
		datasourceId_ = "";
		columns_ = java.util.Collections.emptyList();
		vendor_ = "";
		status_ = "";
		author_ = "";
		fileFormat_ = 0;*/
		return data.getDomaindataId();
	}

	@Override
	public KusciaDataVo queryDomainDataVo(GrpcApiInfo apiInfo, String nodeId, String domaindataId) {
		try {
			KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
			Domaindata.QueryDomainDataRequest request = Domaindata.QueryDomainDataRequest
	        .newBuilder()
	        .setData(Domaindata.QueryDomainDataRequestData.newBuilder().setDomainId(nodeId).setDomaindataId(domaindataId))
	        .build();
			QueryDomainDataResponse response = new KusciaDomainDataRpcImpl(apiProperties).queryDomainData(request);
			if(null != response) {
				Domaindata.DomainData data = response.getData();
				//logger.info("data:{}", data);
				Map <String, String> attrMap = data.getAttributesMap();
				
				List<KusciaDataValueHeaderVo> headers = new ArrayList<KusciaDataValueHeaderVo>();
				Map<String, List<KusciaDataValueItemVo>> headerItemMap = new HashMap<String, List<KusciaDataValueItemVo>>();
				
				if(null != attrMap && attrMap.containsKey("dist_data") && "report".equals(data.getType())) {
					JSONArray tabsArray = JSON.parseObject(attrMap.get("dist_data")).getJSONObject("meta").getJSONArray("tabs");
					Object tabsArray0 = tabsArray.get(0);
					JSONArray divsArray = JSON.parseObject(tabsArray0.toString()).getJSONArray("divs");
					Object divsArray0 = divsArray.get(0);
					JSONArray childrenArray = JSON.parseObject(divsArray0.toString()).getJSONArray("children");
					Object childrenArray0 = childrenArray.get(0);
					JSONObject tableObj = JSON.parseObject(childrenArray0.toString()).getJSONObject("table");
					JSONArray headersStrArray = tableObj.getJSONArray("headers");
					for (Object obj : headersStrArray) {
						if(obj instanceof JSONObject) {
							JSONObject jobj = (JSONObject) obj;
							KusciaDataValueHeaderVo headerVo = jobj.toJavaObject(KusciaDataValueHeaderVo.class);
							headers.add(headerVo);
						}
					}
					JSONArray rowsStrArray = tableObj.getJSONArray("rows");
					for (Object obj : rowsStrArray) {
						if(obj instanceof JSONObject) {
							JSONObject jobj = (JSONObject) obj;
							String name = jobj.getString("name");
							JSONArray items = jobj.getJSONArray("items");
							List<KusciaDataValueItemVo> itemList = new ArrayList<KusciaDataValueItemVo>();
							for (Object item : items) {
								if(item instanceof JSONObject) {
									JSONObject itemj = (JSONObject) item;
									KusciaDataValueItemVo valueVo = itemj.toJavaObject(KusciaDataValueItemVo.class);
									itemList.add(valueVo);
								}
							}
							headerItemMap.put(name, itemList);
						}
					}
				}
				//logger.info("headers:{}", JSON.toJSON(headers));
				//logger.info("headerItemMap:{}", JSON.toJSON(headerItemMap));
				
				KusciaDataVo vo = new KusciaDataVo();
				vo.setAuthor(data.getAuthor());
				vo.setStatus(data.getStatus());
				vo.setDomainDataId(data.getDomaindataId());
				vo.setName(data.getName());
				vo.setRelativeUri(data.getRelativeUri());
				vo.setType(data.getType());
				vo.setDatasourceId(data.getDatasourceId());
				List <DataColumn> list = data.getColumnsList();
				if(null != list && list.size() > 0) {
					List<KusciaDataColumnVo> columns = new ArrayList<KusciaDataColumnVo>();
					for (DataColumn dataColumn : list) {
						KusciaDataColumnVo column = new KusciaDataColumnVo();
						column.setName(dataColumn.getName());
						column.setType(dataColumn.getType());
						column.setComment(dataColumn.getComment());
						columns.add(column);
					}
					vo.setColumns(columns);
				}
				vo.setHeaders(headers);
				vo.setItems(headerItemMap);
				return vo;
			}
		} catch (Exception e) {
			logger.error("查询数据信息，组装异常:{}", e);
			return null;
		}
		return null;
	}

	@Override
	public void batchQueryDomainData(GrpcApiInfo apiInfo) {
		KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
		
	}

	@Override
	public void listDomainData(GrpcApiInfo apiInfo, String nodeId, @Nullable String vendor) {
		KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
		Domaindata.ListDomainDataRequestData.Builder builder = Domaindata.ListDomainDataRequestData.newBuilder()
                .setDomaindataType(DATA_TYPE_TABLE)
                .setDomainId(nodeId);
        if (vendor != null) {
            builder.setDomaindataVendor(vendor);
        }
		ListDomainDataRequest request = Domaindata.ListDomainDataRequest.newBuilder()
                .setData(builder.build()).build();
		ListDomainDataResponse response = new KusciaDomainDataRpcImpl(apiProperties).listDomainData(request);
        Domaindata.DomainDataList datas = response.getData();
		logger.info("datas:{}", datas);
	}
	
}
